#pragma once

#include "../Container/SLList.h"

#include "Matrix4x4.h"

////////////////////////////////////////////////////////////////////////////////////////////////////
/// <Summary>	Frame  </Summary>
/// 
/// <purpose>	Math utility to hold and manipulate a heirachy of matrices	</purpose>
////////////////////////////////////////////////////////////////////////////////////////////////////

class Frame
{
	/// <Summary> The local matrix </Summary>
	Matrix4x4 localMatrix;

	/// <Summary> The world matrix </Summary>
	Matrix4x4 worldMatrix;

	/// <Summary> The parent frame </Summary>
	Frame* parentFrame;

	/// <Summary> The children </Summary>
	SLList<Frame*> children;

	/// <Summary> The dirty flag </Summary>
	bool dirtyFlag;

private:

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Sets the dirty flag for this object and all its children </Summary>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	void Dirty(void);

public:

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Default constructor </Summary>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	Frame(void);

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Default destructor </Summary>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	~Frame(void) {}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Gets the world matrix </Summary>
	///
	/// <Return>	The world matrix </Return>
	/// 
	/// <Remarks>	This is returned as a constant and should not be directly changed	</Remarks>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	const Matrix4x4& GetWorldMatrix();

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Gets the local matrix </Summary>
	///
	/// <Return>	The local matrix </Return>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	Matrix4x4& GetLocalMatrix();

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Sets the local matrix </Summary>
	///
	/// <Param name="mat">	The matrix </Param>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	void SetLocalMatrix(const Matrix4x4* mat);

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Sets the parent </Summary>
	///
	/// <Param name="parent">	The new parent </Param>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	void SetParent(Frame* parent);

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Equality operator </Summary>
	///
	/// <Param name="rightFrame"> The frame on the right side </Param>
	///
	/// <Return>	true if the parameters are considered equivalent. </Return>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	bool operator==(Frame& rightFrame)
	{
		const Matrix4x4& left = GetWorldMatrix();
		const Matrix4x4& right = rightFrame.GetWorldMatrix();

		for(unsigned index = 0; index < 16; ++index)
		{
			if(left.MA[index] != right.MA[index])
				return false;
		}

		return true;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <Summary>	Non-Equality operator </Summary>
	///
	/// <Param name="rightFrame"> The frame on the right side </Param>
	///
	/// <Return>	true if the parameters are not considered equivalent </Return>
	////////////////////////////////////////////////////////////////////////////////////////////////////
	bool operator!=(Frame& rightFrame)
	{
		return !this->operator==(rightFrame);
	}
};